home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Diamond Collection / The Diamond Collection (Software Vault)(Digital Impact).ISO / cdr40 / x1j4_src.zip / TNL3.C < prev    next >
Text File  |  1995-01-15  |  49KB  |  1,179 lines

  1. /*****************************************************************************/
  2. /*                                              */
  3. /*                                         */
  4. /*    *****              *****                      */
  5. /*     *****            *****                         */
  6. /*       *****          *****                         */
  7. /*         *****        *****                         */
  8. /*  ***************      ***************                     */
  9. /*  *****************    *****************                     */
  10. /*  ***************      ***************                     */
  11. /*         *****        *****       TheNet                    */
  12. /*       *****          *****       Portable. Compatible.         */
  13. /*     *****            *****       Public Domain             */
  14. /*    *****              *****    NORD><LINK                  */
  15. /*                                         */
  16. /* This software is public domain ONLY for non commercial use                */
  17. /*                                                                           */
  18. /*                                         */
  19. /*****************************************************************************/
  20.  
  21. /* Level 3, Routing                                 */
  22. /* Version 1.01                                                              */
  23. /* Hans Georg Giese, DF2AU, Hinter dem Berge 5, 3300 Braunschweig         */
  24. /* 14-MAY-88                                     */
  25. /* Modified G8KBB April 1991 
  26.  *     include support for bank switching in TNC2
  27.  *     use register keyword for code efficiency
  28.  *     use all.h header file
  29.  *     make nodes broadcast on ports optional
  30.  *     implement modified nodes bcast algo conditionally on MODIFIED
  31.  *     implement optional RS232 nodes broadcast interval on MODIFIED
  32.  *     include level 3 stats optionally on STATSCMD
  33.  *     implement access control functions optionally on ACL definition
  34.  *     remove unnecessary '== 1' and similar constructs
  35.  *     add integrity checking rather than using isrout()
  36.  *     add noslime controls
  37.  *     use faster macro for cpy6ch & move4b if feasible
  38.  *
  39.  * September 1993 - released as TheNet X-1J
  40.  */
  41.  
  42. #include "all.h"
  43. #include "tntyp.h"        /* Definition der Typen                 */
  44.  
  45. #ifdef BANKED
  46. #define EXTERN extern
  47. #else
  48. #define EXTERN
  49. #endif
  50.  
  51. #include "tnl3v.h"        /* Definition der eigenen Variablen         */
  52. #include "tnl3e.h"        /* externe Deklarationen             */
  53.  
  54. /*---------------------------------------------------------------------------*/
  55. /* Strings fuer Level3                                 */
  56. char    brodes[] =                 /* Ziel (Rundsprueche)       */
  57.                                                 /* ASCII Call                */
  58.                                                 /* SSID links geschoben      */
  59.            {'N','O','D','E','S',' ','\140'};
  60. char    brodil[] = {'\000'};            /* Digiliste (Rundsprueche)  */
  61.                                                 /* Call im Standardformat    */
  62.                                                 /* Listenende = 0            */        
  63. #ifndef BANKED
  64. char    nulide[] =                /* leerer Ident             */
  65.                    {' ',' ',' ',' ',' ',' '};
  66. #else
  67. extern    char nulide[];
  68. #endif
  69.  
  70. /*---------------------------------------------------------------------------*/
  71. VOID    l3init()        /* Level 3 initialisieren             */
  72.   {
  73.   register nbrtyp *nbrpoi;    /* Pointer auf Nachbarn                 */
  74.  
  75.   numdes = 0;            /* Ziel Liste ist leer                 */
  76.   inithd(&l3rxfl);        /* Liste empfangene Frames loeschen         */
  77.   inithd(&l3txl);        /* Liste zu sendende Frames loeschen         */
  78. #ifdef STATSCMD
  79.   l3gwcnt[0] = l3gwcnt[1] = 0;  /* clear level 3 stats counters              */
  80. #endif
  81.   if (!iswarm())        /* nur im Kaltstart                 */
  82.     {
  83.       inithd(&destil);        /* Liste Ziele loeschen                 */
  84.       inithd(&neigbl);        /* Liste Nachbarn loeschen             */
  85.       maxdes = DEFDES;        /* Ziele maximal                 */
  86.       broint = DEFBRI;        /* Rundspruch Intervall                 */
  87.       obcini = DEFOBC;        /* Abwesenheitszaehler                 */
  88.       obcbro = DEFOBB;        /* maximale Abwesenheit fuer Rundspruch         */
  89.       worqua = DEFWQU;        /* Qualitaet fuer Rundspruch minimal         */
  90.       timliv = DEFTLI;        /* Paketlebensdauer                 */
  91.       ch0qua = DEFCH0;        /* Kanal 0 Qualitaet                 */
  92.       ch1qua = DEFCH1;        /* Kanal 1 Qualitaet                 */
  93. #ifdef MODIFIED
  94.       brochn = DEFBCN;           /* channels for node broadcast control      */
  95.       br1int = DEFBR1;           /* default nodes bcast interval in seconds  */
  96.       broalg = DEFALG;           /* default algorithm control flags          */
  97. #endif
  98.     }
  99.   else                /* Warmstart                     */
  100.     {
  101.  
  102.       /* integrity checking is done here for all tables. This should be
  103.        * for all linked lists of tables that should be maintained. These
  104.        * are defined according to the options compiled in but include the
  105.        * ACL, netrom neighbour & destination, IP route and ARP tables.
  106.        * Calling integrity with a null parameter instructs it to check
  107.        * that the tables are linked and do not point to rubbish.
  108.        */
  109. #ifdef INTEGRITY
  110.       integrity( NULL );
  111. #endif
  112.       for (despoi  = (nodtyp *) destil.lnext;    /* Zielliste bearbeiten         */
  113.            despoi != (nodtyp *) &destil.lnext;
  114.            despoi  = (nodtyp *) despoi->nodlnk.lnext)
  115.         {
  116. #ifdef PK96
  117.     kick_wdog();
  118. #endif
  119.           if (despoi->nodcal[0] != 0)    /* Eintrag belegt?             */
  120.             {
  121.               numdes += 1;        /* ein Ziel mehr             */
  122.               despoi->actrou = 0;    /* kein aktiver Weg             */
  123.               inithd(&despoi->nodinf);    /* keine Info fuer dieses Ziel         */
  124.             }
  125.           else                /* leerer Eintrag             */
  126.             {
  127.               unlink((despoi = (nodtyp *)despoi->nodlnk.lprev)->nodlnk.lnext);
  128.             }
  129.         }
  130.     for (nbrpoi  = (nbrtyp *) neigbl.lnext;    /* Nachbarn Liste bearbeiten */
  131.          nbrpoi != (nbrtyp *) &neigbl.lnext;
  132.          nbrpoi  = (nbrtyp *) nbrpoi->nbrlnk.lnext)
  133.       {
  134.         nbrpoi->nbrl2l = 0;    /* Querverweis in L2Link loeschen         */
  135.       }
  136.     }
  137.   brotim = broint > 60 ? broint - 60 : 0; /* set node b'cast current timer   */
  138. #ifdef MODIFIED
  139.   br1tim = br1int > 60 ? br1int - 60 : 0; /* set RS232 nodes bcast timer     */
  140. #endif
  141.   }
  142.  
  143. /*---------------------------------------------------------------------------*/
  144. VOID    l3serv()        /* Level 3 Service                 */
  145.   {
  146.   char       orgnod[7];        /* Call des Quellknotens             */
  147.   char       desnod[7];        /* Call des Zielknotens                 */
  148.   char       beaide[6];        /* Ident des Rundspruch sendenden Knotens    */
  149.   char       nbrcal[7];        /* Call des Nachbarn                 */
  150.   char       *rxnxt;        /* erstes Zeichen im Frame             */
  151.   char       *nxtsav;        /* Zwischenspeicher fuer erstes Zeichen         */
  152.   BOOLEAN  destin;        /* aktuelles Ziel                 */
  153.   register unsigned cnt;    /* Scratch Zaehler                 */
  154.   register mhtyp *mbhd;        /* Kopf des aktuellen Frames             */
  155.   unsigned chaqua;        /* Qualitaet des aktuellen Kanals         */
  156.   unsigned getsav;        /* Zwischenspeicher fuer Getcount         */
  157.   register unsigned rxgetc;    /* Getcount des Frames                 */
  158.  
  159. /*=== empfangene Frames verarbeiten                      ===*/
  160.   while ((mbhd = (mhtyp *) l3rxfl.lnext) != (mhtyp *) &l3rxfl) /* Liste leer?*/
  161.     {
  162.     unlink(mbhd);        /* Frame aus Kette loesen             */
  163.     if ((mbhd->pid & 0xff) == PID_NETROM) /* PID stimmt?             */
  164.       {
  165.       rxnxt = mbhd->nxtchr;    /* erstes Zeichen des Frames und         */
  166.       rxgetc = mbhd->getcnt;    /* Getcount merken                 */
  167.  
  168.       if (mbhd->l2lnk != 0)    /* Info Frame?                     */
  169.  
  170. /*------------------------------*/
  171. /*--- Info Frame             ---*/
  172. /*------------------------------*/
  173.         {
  174.         if ((getfid(orgnod, mbhd) /*== 1*/) /* Call des Quellknotens holen     */
  175.           &&(getfid(desnod, mbhd) /*== 1*/) /* Call des Zielknotens holen     */
  176.           &&(mbhd->getcnt < mbhd->putcnt)) /* Info im Frame?             */
  177.           {
  178.             getchr(mbhd);    /* Restlebensdauer ueberlesen             */
  179.             nxtsav = mbhd->nxtchr; /* Position im Frame merken             */
  180.             getsav = mbhd->getcnt;
  181.             takfhd(mbhd);    /* Header zerlegen                 */
  182.             mbhd->nxtchr = nxtsav; /* wieder auf alten Stand             */
  183.             mbhd->getcnt = getsav;
  184.  
  185.             if ((cmpid(myid, orgnod) == 0)    /* kein eigenes Frames         */
  186.               &&(isgood() /*== TRUE*/)        /* und gute Qualitaet         */
  187.           &&(
  188.                 ((destin = iscall(orgnod)) == FALSE)
  189.             ||(istweg(&txfhdr[14], &rxfhdr[7], rxfprt) == ERROR)
  190.                 )
  191. #ifdef MODIFIED
  192.               && ( destin || (( no_slime & 2 ) == 0 ))
  193. #endif
  194.               )
  195.               {
  196.                 chgnod('+', obcini, 0, rxfprt, &txfhdr[14], &rxfhdr[7],
  197.                        (destin == FALSE)? &nulide[0] : &despoi->nodide[0],
  198.                        orgnod);        /* Zielliste auf neuen Stand bringen */
  199.               }
  200.  
  201.             if (cmpid(myid, desnod) /*== 1*/)    /* Frame fuer mich?         */
  202.               {
  203.                 relink(mbhd, l4rxfl.lprev);    /* dann an Level 4 geben     */
  204.                 continue;            /* naechstes Frame         */
  205.               }
  206.  
  207.             if (iscall(desnod) /*== 1*/ )    /* Ziel bekannt?         */
  208.               {
  209.                 if (--*(mbhd->nxtchr -1) != 0)    /* noch Restlebensdauer?     */
  210.                   {
  211.                     mbhd->nxtchr = rxnxt;    /* auf Transportheader         */
  212.                     mbhd->getcnt = rxgetc;
  213.                     if ((despoi->actrou != 0)    /* aktiver Weg zum Ziel?     */
  214.                       &&(mbhd->l2lnk ==
  215.                          despoi->weg[despoi->wegnr].nachba->nbrl2l))
  216.                       {
  217.                         despoi->actrou &=0xfff8;
  218.                         despoi->actrou |= 0x02;
  219.                       }
  220.                     if ((cmpid(myid, orgnod) == 0)
  221.                       || ((despoi->actrou & 0x07) == 2))
  222.                       {
  223. #ifdef STATSCMD
  224.                         l3gwcnt[0]++; /* bump gateway stats counter */
  225. #endif
  226. #ifdef L3MONITOR
  227.                         checkheard( &l3heardl, orgnod, l3mhlcnt );
  228.                         if ( l3mhlcnt )
  229.                             cpyid( mhptr->l3dest, desnod );
  230. #endif
  231. #ifdef ACL
  232.                         if( ( acl_mask & ACL_BAR_L3_RELAY ) &&
  233.                             (( acl_entry( orgnod ) & ACL_BAR_L3_RELAY )
  234.                              ||
  235.                             ( acl_entry( desnod ) & ACL_BAR_L3_RELAY ) ))
  236.                             dealmb( mbhd );
  237.                         else
  238. #endif
  239.                         {
  240. #ifdef PK96
  241.                             sta_led_on();
  242. #endif
  243.                             todest(mbhd);   /* Info absetzen                     */
  244. #ifdef PK96
  245.                             sta_led_off();
  246. #endif
  247.                         }
  248.                         continue;
  249.                       }            /* Info kann abgesetzt werden         */
  250.                   }            /* noch Restlebensdauer             */
  251.               }                /* Ziel ist bekannt             */
  252.          }                /* Info ist im Frame             */
  253.     }                    /* es ist ein I-Frame             */
  254.  
  255. /*--------------------------------------*/
  256.       else                /* UI Frame                 */
  257.         {
  258.           if (worqua != 0)        /* darf Auswertung erfolgen?         */
  259.             {
  260.               takfhd(mbhd);        /* Header zerlegen             */
  261.               mbhd->nxtchr = rxnxt;    /* zurueck auf Anfang             */
  262.               mbhd->getcnt = rxgetc;
  263.  
  264.               if (isgood() == TRUE)
  265.                 {
  266.                   if ((mbhd->getcnt < mbhd->putcnt)    /* Info im Frame?    */
  267.                     &&((getchr(mbhd) & 0xff) == 0xff)    /* stimmt Signatur?  */
  268.                     &&(ge6chr(beaide, mbhd) /*== 1*/)    /* Ident des Knotens */
  269.                     &&(chgnod('+', obcini, qualty, rxfprt, &txfhdr[14],
  270.                        &rxfhdr[7], &beaide[0], &rxfhdr[7]) /*== 1*/))
  271.                     {
  272.                       while ((getfid(desnod, mbhd) /*== 1*/) /* Rest des Frames  */
  273.                             && (ge6chr(beaide, mbhd) /*==1*/)
  274.                             && (getfid(nbrcal, mbhd) /*== 1*/)
  275.                             && (mbhd->getcnt < mbhd->putcnt))
  276.                         {
  277.                           chaqua = getchr(mbhd) & 0xff;
  278.                           if (cmpid(myid, desnod) == 0)   /* selbst Ziel?    */
  279.                             {
  280.                               if ((chaqua = (((chaqua * qualty) +128) / 256))
  281.                                 >= worqua)
  282.                                 {
  283.                                   if (cmpid(myid, nbrcal) /*== 1*/) 
  284.                                       chaqua = 0;
  285.                                   if (chgnod('+', obcini, chaqua, rxfprt,
  286.                                       &txfhdr[14], &rxfhdr[7],
  287.                                       ((chaqua == 0) && (iscall(desnod) != 0))?
  288.                                         &despoi->nodide[0] : &beaide[0],
  289.                                       desnod) == 0) break;
  290.                                 }    /* Qualitaet gut genug fuer Update   */
  291.                             }        /* nicht selbst das Ziel         */
  292.                         }        /* bis Framenende             */
  293.  
  294.                       if (nbrpoi != NULL)
  295.                         {        /* Nachbar definiert             */
  296.                         for (despoi  = (nodtyp *) destil.lnext; /* Ziel?     */
  297.                              despoi != (nodtyp *) &destil.lnext;
  298.                              despoi  = (nodtyp *) despoi->nodlnk.lnext)
  299.                           {
  300.                             if (despoi->actrou != 0)
  301.                               {            /* aktiver Weg zum Ziel?     */
  302.                                 for (cnt = 0;    /* alle Wege des Zieles         */
  303.                                   despoi->wege > cnt;
  304.                                   ++cnt)
  305.                                   {
  306.                                     if (despoi->weg[cnt].nachba == nbrpoi)
  307.                                       {    /* fuehrt der Weg ueber diesen Nachb */
  308.                                         if (despoi->wegnr > cnt)
  309.                                           { /* gibt es einen besseren Weg?   */
  310.                                             despoi->wegnr = cnt;
  311.                                             makrou(); /* diesen Weg versuchen*/
  312.                                           }    /* es gibt einen besseren Weg*/
  313.                                         break;
  314.                                       }    /* Weg fuehrt ueber diesen Nachbarn  */
  315.                                   }    /* dieser Weg bearbeitet         */
  316.                               }        /* aktiver Weg existiert         */
  317.                           }        /* dieses Ziel bearbeitet         */
  318.                       }            /* Weg geht ueber einen Nachbarn     */
  319.                     }            /* Signatur ist gut             */
  320.                 }            /* Qualitaet des Kanals stimmt         */
  321.             }                /* Auswertung zulaessig             */
  322.         }                /* ist UI Frame                 */
  323.       }                    /* PID stimmt                 */
  324.     dealmb(mbhd);            /* Frame ist bearbeitet, wegwerfen   */
  325.   }                    /* Frames in der Kette             */
  326.  
  327. /*=== zu sendende Frames verarbeiten                      ===*/
  328.   while ((mbhd = (mhtyp *) l3txl.lnext) != (mhtyp *) &l3txl.lnext) { /* leer?*/
  329.     unlink(mbhd);        /* Frame aushaengen                 */
  330.     despoi = (nodtyp *) mbhd->l2lnk;    /* Pointer auf Nachbarn             */
  331.     if ((despoi->nodcal[0] != 0) /* Ziel definiert                 */
  332.       && (nmbfre > 64)) {    /* und Platz im Speicher             */
  333.       rwndmb(mbhd);        /* alle Pointer auf Ausgangsstellung         */
  334.       getchr(mbhd);        /* alles initialisieren                 */
  335.       --mbhd->nxtchr;
  336.       rxgetc = mbhd->putcnt;    /* Framelaenge merken                 */
  337.       mbhd->putcnt = 1;        /* auf Anfang                     */
  338.       putfid(myid, mbhd);    /* Absender ins Frame                 */
  339.       putfid(&despoi->nodcal[0], mbhd); /* Ziel ins Frame             */
  340.       *(mbhd->nxtchr -1) |= 1;    /* Ende der Adresse setzen             */
  341.       putchr(timliv, mbhd);    /* Lebensdauer setzen                 */
  342.       mbhd->putcnt = rxgetc;    /* Putcount zurueck                 */
  343.       rwndmb(mbhd);        /* Pointer wieder aufziehen             */
  344.       todest(mbhd);        /* weg damit                     */
  345.       }
  346.     else dealmb(mbhd);        /* geht nicht, Frame vernichten             */
  347.     }
  348.  
  349. /*=== sonstige Funktionen                          ===*/
  350.   for (despoi  = (nodtyp *) destil.lnext;        /* Zielliste bearbeiten                 */
  351.        despoi != (nodtyp *) &destil.lnext;
  352.        despoi  = (nodtyp *) despoi->nodlnk.lnext) {
  353.     switch (despoi->actrou & 0x07) { /* ueber Wegstatus verzweigen         */
  354. /*------------------------------*/
  355.       case 2:            /* Fehler aufgetreten, neuen Weg nehmen         */
  356.         if (++despoi->wegnr >= despoi->wege) {
  357.           if ((despoi->actrou & 0x80) == 0)
  358.             despoi->wegnr = 0;
  359.           else {
  360.             destot();        /* Ziel nicht erreichbar, Frames wegwerfen   */
  361.             break;
  362.           } }
  363.         makrou();        /* Weg aufbauen                     */
  364.         break;
  365.         
  366. /*------------------------------*/
  367.       case 3:            /* Info Transfer laeuft                 */
  368.         while ((mbhd = (mhtyp *) despoi->nodinf.lnext)
  369.                     != (mhtyp *) &despoi->nodinf)
  370.          {
  371.           unlink(mbhd);        /* Frame aus Kette holen             */
  372.           mbhd->pid = PID_NETROM;/* PID setzen                     */
  373.           relink(mbhd,
  374.             (lnkpoi = despoi->weg[despoi->wegnr].nachba->nbrl2l)
  375.             ->sendil.lprev);    /* Frame in L2 umhaengen             */
  376.           ++lnkpoi->tosend;    /* ein Frame mehr senden             */
  377.           lnkpoi->noatou = ininat; /* Timeout setzen                 */
  378.           }
  379.         break;
  380.         
  381. /*------------------------------*/
  382.       case 4:            /* */
  383.         makrou();        /* Weg aufbauen                     */
  384.         break;
  385.  
  386. /*------------------------------*/
  387.       default:            /* leer oder connect laeuft             */
  388.         break;
  389.         
  390.   } } }
  391.  
  392. /*---------------------------------------------------------------------------*/
  393. VOID    l2tol3(status)        /* Level 2 meldet neuen Status             */
  394. unsigned status;        /* 0=nicht verwendet, 1=connected         */
  395.                 /* 2=disconnected, 3=busy, 4=Failure         */
  396.   {
  397.   register unsigned  wegsts;    /* Status des aktuellen Weges             */
  398.   register nbrtyp    *nbrpoi;    /* Pointer auf Nachbarn                 */
  399.  
  400.   if (status < 5)        /* nicht alles verwenden             */
  401.    {
  402.     for (despoi  = (nodtyp *) destil.lnext;    /* gemeldeten Link suchen    */
  403.          despoi != (nodtyp *) &destil.lnext;
  404.          despoi  = (nodtyp *) despoi->nodlnk.lnext)
  405.      {
  406.       if (((wegsts = despoi->actrou & 0x07) != 0) /* aktiver Weg?         */
  407.             && ((despoi->weg[despoi->wegnr].nachba)->nbrl2l == lnkpoi))
  408.             {
  409.               if (status == 1)        /* Connect gemeldet             */
  410.                 {
  411.                   if (wegsts == 1)    /* und war auch gefordert         */
  412.                     despoi->actrou = 3;    /* neuer Status des Zieles: connected*/
  413.                 }
  414.               else
  415.                 {
  416.                   if (wegsts != 4)
  417.                     {
  418.                       despoi->actrou &= 0xfff8;        /* Busy:         */
  419.                       despoi->actrou |= 0x02; /* neuer Status: anderen Weg   */
  420.                     }
  421.                 }
  422.             }
  423.         }
  424.       if (status != 1)            /* bei Busy / Failure             */
  425.         {
  426.           for (nbrpoi  = (nbrtyp *) neigbl.lnext; /* Nachbar Liste absuchen  */
  427.                nbrpoi != (nbrtyp *) &neigbl.lnext;
  428.                nbrpoi  = (nbrtyp *) nbrpoi->nbrlnk.lnext)
  429.             {
  430.               if (nbrpoi->nbrl2l == lnkpoi)
  431.                 nbrpoi->nbrl2l = 0;    /* Querverweis loeschen             */
  432.             }
  433.         }
  434.     }
  435.   }
  436.  
  437. /*---------------------------------------------------------------------------*/
  438. #ifdef MODIFIED
  439. /* brosrv()
  440.  * This routine is called to make nodes b'casts. If the modified
  441.  * version is used, it adds extra features as described in the
  442.  * overview guide. To enable this its structure is different !
  443.  */
  444. VOID    brosrv()        /* Rundspruchservice                 */
  445.                 /* jede Sekunde aufgerufen             */
  446. {
  447.   register unsigned cnt;    /* Zaehler             */
  448.   register unsigned mask;
  449.   register wegtyp   *route;    /* aktueller Weg             */
  450.  
  451.   if( br1int != 0 )        /* assuming that the function is running,    */
  452.     if( ++br1tim >= br1int )    /* then bump timer and see if period expired */
  453.     {                /* if so, clear counter & do RS232 nodes     */
  454.       br1tim = 0;
  455.       if( brochn & 2 )
  456.         bronpo( ASYNPORT );
  457.     }
  458.   if (broint != 0)        /* Rundspruch erlaubt?                 */
  459.   {
  460.     if (++brotim >= broint)    /* Zeit zum Senden gekommen?             */
  461.     {
  462.       brotim = 0;        /* Uhr ruecksetzen                 */
  463.       for (despoi  = (nodtyp *) destil.lnext;    /* Zielliste absuchen         */
  464.            despoi != (nodtyp *) &destil.lnext;
  465.            despoi  = (nodtyp *) despoi->nodlnk.lnext)
  466.       {
  467.         if (despoi->nodcal[0] != 0) /* Eintrag belegt?             */
  468.         {
  469.           if (obcini != 0)    /* wenn Abwesenheitszaehler gefuehrt wird    */
  470.           {
  471.             for (cnt = 0; cnt < despoi->wege; ++cnt) /* alle Wege testen     */
  472.             {
  473.               if (((route = &despoi->weg[cnt])->obscnt != 0) /* gueltig?     */
  474.                 &&(--(route->obscnt) == 0))   /* gerade auf 0 angekommen?    */
  475.               {
  476.                 delrou(cnt);    /* dann loeschen                 */
  477.                 --cnt;        /* ein Weg weniger                 */
  478.               } 
  479.             }
  480.           } 
  481.         } 
  482.       }
  483.       /* for each port, if bcast enabled for that port, and if RS232 nodes
  484.        * broadcasts are going at a different rate and this is not the RS232
  485.        * port, then broadcast nodes
  486.        */
  487.       for( cnt = 0, mask = 1; cnt < NUMPORTS; cnt++, mask <<= 1 )
  488.         if( ( brochn & mask ) && ( br1int == 0 || cnt != ASYNPORT ))
  489.           bronpo( cnt );
  490.     }
  491.   }
  492. }
  493.  
  494. /* ---------------------------------------------------------------------------
  495.  * This is the per channel nodes broadcast routine.
  496.  * It is called by brosrv() to do a b'cast on a specified channel.
  497.  *
  498.  */
  499. VOID bronpo( kanal )
  500. register unsigned kanal;
  501. {
  502.   register mhtyp    *mbhd;        /* Buffer fuer Meldung             */
  503.   register wegtyp   *route;        /* aktueller Weg             */
  504.   unsigned algorithm, nohash;
  505.   
  506.   /* if algorithm flag is TRUE, then do not broadcast a node if its best
  507.    * quality neighbour is on the same port
  508.    */
  509.   algorithm = broalg & ( 1 << kanal );
  510.   nohash = nohashnode & ( 1<< kanal );
  511.  
  512.   mbhd = brobuf();        /* Buffer besorgen                 */
  513.   for (despoi  = (nodtyp *) destil.lnext;    /* Zielliste absuchen         */
  514.        despoi != (nodtyp *) &destil.lnext;
  515.        despoi  = (nodtyp *) despoi->nodlnk.lnext) 
  516.   {
  517.     if (despoi->nodcal[0] != 0) /* Eintrag belegt?             */
  518.     {
  519.       if (((route = &despoi->weg[0])->qualit != 0)        /* Qualitaet */
  520.             &&( algorithm == 0 || route->nachba->nbrpor != kanal )
  521.             &&( nohash != 0 ? despoi->nodide[0] != '#' : 1 ) 
  522.             &&((route->obscnt == 0) /* muss sein, Eintrag permanent oder     */
  523.             || ((route->obscnt & 0xff) >= obcbro))) /* gut genug         */
  524.       {
  525.         if (mbhd == 0)    /* ggfs neuen Buffer besorgen             */
  526.           mbhd = brobuf();
  527.  
  528.         putfid(&despoi->nodcal[0], mbhd); /* Call des Zieles         */
  529.         pu6chr(&despoi->nodide[0], mbhd); /* Ident des Zieles         */
  530.         putfid(&route->nachba->nbrcal[0], mbhd); /* Nachbar des Zieles   */
  531.         putchr(route->qualit, mbhd); /* Qualitaet zum Ziel             */
  532.         if ((mbhd->putcnt + 21) > 256)     /* droht Ueberlauf?         */
  533.         {
  534.           sdbufr(mbhd, kanal);    /* dann Buffer senden                 */
  535.               mbhd = 0;        /* Buffer ist weg                 */
  536.         }
  537.       }
  538.     }
  539.   }
  540.   if (mbhd != 0)        /* noch Reste im Buffer?             */
  541.     sdbufr(mbhd, kanal);        /* dann senden                     */
  542. }
  543.  
  544. /*---------------------------------------------------------------------------*/
  545. VOID    sdbufr(mbhd, kanal)        /* Buffer als Rundspruch senden             */
  546. register mhtyp    *mbhd;
  547. {
  548.    mbhd->pid = PID_NETROM;    /* PID = Level3                     */
  549.    rwndmb(mbhd);        /* Pointer aufziehen                 */
  550.    sdui(&brodil[0], &brodes[0], &myid[0], kanal, mbhd);   /* Level2 sendet  */
  551.    dealmb(mbhd);            /* Buffer wieder freigeben             */
  552. }
  553.  
  554. #else
  555. /* --------------------------------------------------------------------------
  556.  * this is the original ( almost ) brosrv()
  557.  */
  558. VOID    brosrv()        /* Rundspruchservice                 */
  559.                 /* jede Sekunde aufgerufen             */
  560.   {
  561.   register unsigned cnt;    /* Zaehler                     */
  562.   register mhtyp    *mbhd;    /* Buffer fuer Meldung                 */
  563.   register wegtyp   *route;    /* aktueller Weg                 */
  564.  
  565.   if (broint != 0) {        /* Rundspruch erlaubt?                 */
  566.     if (++brotim >= broint) {    /* Zeit zum Senden gekommen?             */
  567.       brotim = 0;        /* Uhr ruecksetzen                 */
  568.       mbhd = brobuf();        /* Buffer besorgen                 */
  569.  
  570.       for (despoi  = (nodtyp *) destil.lnext;    /* Zielliste absuchen         */
  571.            despoi != (nodtyp *) &destil.lnext;
  572.            despoi  = (nodtyp *) despoi->nodlnk.lnext) {
  573.         if (despoi->nodcal[0] != 0) { /* Eintrag belegt?             */
  574.           if (obcini != 0) {    /* wenn Abwesenheitszaehler gefuehrt wird    */
  575.             for (cnt = 0;    /* alle Wege testen                 */
  576.                  cnt < despoi->wege;
  577.                  ++cnt) {
  578.               if (((route = &despoi->weg[cnt])->obscnt != 0) /* gueltig?     */
  579.                 &&(--(route->obscnt) == 0)) { /* gerade auf 0 angekommen?    */
  580.                 delrou(cnt);    /* dann loeschen                 */
  581.                 --cnt;        /* ein Weg weniger                 */
  582.               } }
  583.             if (despoi->nodcal[0] == 0) /* gibt es den Weg noch?         */
  584.               continue;
  585.             }
  586.           if (((route = &despoi->weg[0])->qualit != 0)        /* Qualitaet */
  587.             &&((route->obscnt == 0) /* muss sein, Eintrag permanent oder     */
  588.             || ((route->obscnt & 0xff) >= obcbro))){ /* gut genug         */
  589.  
  590.             if (mbhd == 0)    /* ggfs neuen Buffer besorgen             */
  591.               mbhd = brobuf();
  592.  
  593.             putfid(&despoi->nodcal[0], mbhd); /* Call des Zieles         */
  594.             pu6chr(&despoi->nodide[0], mbhd); /* Ident des Zieles         */
  595.             putfid(&route->nachba->nbrcal[0], mbhd); /* Nachbar des Zieles   */
  596.             putchr(route->qualit, mbhd); /* Qualitaet zum Ziel             */
  597.             if ((mbhd->putcnt + 21) > 256) { /* droht Ueberlauf?         */
  598.               sdbufr(mbhd);    /* dann Buffer senden                 */
  599.               mbhd = 0;        /* Buffer ist weg                 */
  600.               }
  601.             }
  602.         } }
  603.       if (mbhd != 0)        /* noch Reste im Buffer?             */
  604.         sdbufr(mbhd);        /* dann senden                     */
  605.   } } }
  606.  
  607. /*---------------------------------------------------------------------------*/
  608. VOID    sdbufr(mbhd)        /* Buffer als Rundspruch senden             */
  609. mhtyp    *mbhd;
  610.   {
  611.   register unsigned kanal;    /* Kanal, auf dem gesendet wird             */
  612.   mbhd->pid = PID_NETROM;    /* PID = Level3                     */
  613.   for (kanal = 0;
  614.        kanal < 2;        /* auf beiden Kanaelen senden             */
  615.        ++kanal)
  616.     {
  617.       rwndmb(mbhd);        /* Pointer aufziehen                 */
  618.       sdui(&brodil[0], &brodes[0], &myid[0], kanal, mbhd);   /* Level2 sendet  */
  619.     }
  620.   dealmb(mbhd);            /* Buffer wieder freigeben             */
  621.   }
  622.  
  623. #endif /* MODIFIED brosrv() */
  624.  
  625. /*---------------------------------------------------------------------------*/
  626. mhtyp    *brobuf()        /* Buffer fuer Rundspruch besorgen         */
  627.   {
  628.   register mhtyp    *mbhd;        /* Buffer fuer Meldung             */
  629.  
  630.   putchr(0xff, (mbhd = allocb()));    /* Buffer besorgen, Signatur rein    */
  631.   pu6chr(alias, mbhd);            /* Ident in Buffer             */
  632.   return(mbhd);                /* Buffer als Rueckgabe             */
  633.   }
  634.  
  635. /*---------------------------------------------------------------------------*/
  636. BOOLEAN    chgnod(mode, obci, quali, port, digis, nachb, iden, call)
  637.                 /* Zieleintrag aendern                 */
  638. unsigned mode;            /* '+'=neuer Eintrag, '-'=Eintrag loeschen   */
  639. unsigned obci;            /* Abwesenheitszaehler, Initialisierung         */
  640. unsigned quali;            /* Qualitaet des Weges                 */
  641. unsigned port;            /* Port zum Ziel                 */
  642. char     *digis;        /* Digipeaterliste                 */
  643. char     *nachb;        /* Nachbar zum Ziel                 */
  644. char     *iden;            /* Ident des Zieles                 */
  645. char     *call;            /* Rufzeichen des Zieles             */
  646.  
  647.                 /* Rueckgabe:                     */
  648.                 /* TRUE: loeschen verlangt, kein Eintrag da  */
  649.                 /*       aendern war erfolgreich         */
  650.                 /* FALSE: Liste voll                 */
  651.   {
  652.   register unsigned cnt;    /* Scratch Zaehler                 */
  653.   register char     *id1poi;    /* Pointer fuer Call-Ident Vergleich         */
  654.   char       *id2poi;        /* Pointer fuer Call-Ident Vergleich         */
  655.   unsigned rout;        /* aktueller Weg                 */
  656.   register nodtyp   *ziel1;    /* Pointer auf Ziel                 */
  657.   nodtyp   *zielpt;        /* Pointer auf Ziel                 */
  658.  
  659.   zielpt = NULL;
  660.   for (despoi  = (nodtyp *) destil.lnext;    /* Zielliste absuchen         */
  661.        despoi != (nodtyp *) &destil.lnext;
  662.        despoi  = (nodtyp *) despoi->nodlnk.lnext)
  663.     {
  664.     if (despoi->nodcal[0] != 0) { /* Eintrag belegt?                 */
  665.       if (cmpid(&despoi->nodcal[0], call) /*== 1*/) break; /* und passt?         */
  666.       }
  667.     else {            /* freier Eintrag                 */
  668.       if (zielpt == NULL) zielpt = despoi; /* ersten freien Eintrag merken   */
  669.       }
  670.     }
  671.   if ((nodtyp *) &destil.lnext == despoi) {    /* passender Eintrag?         */
  672.     if (mode == '+') {        /* hinzufuegen?                     */
  673.       if (zielpt == 0) {    /* kein freier Platz bisher?             */
  674.         if (numdes < maxdes) {    /* Liste hat noch Platz?             */
  675.           (zielpt = (nodtyp *) allocb())->actrou = 0;   /* initialisieren    */
  676.           zielpt->wege = 0;    /* kein Weg bekannt                 */
  677.           inithd(&zielpt->nodinf); /* keine Info in der Schlange         */
  678.           relink(zielpt, destil.lprev); /* in Zielliste haengen             */
  679.           ++numdes;        /* Liste ist laenger geworden             */
  680.           }
  681.         else return (FALSE);    /* Liste ist voll                 */
  682.         }
  683.       despoi = zielpt;        /* freien (neuen) Platz nehmen             */
  684.       cpyid(&despoi->nodcal[0], call); /* Call eintragen, Rest spaeter         */
  685.       }
  686.     else return (TRUE);        /* loeschen verlangt, Eintrag existiert nicht*/
  687.     }
  688.  
  689. /*------------------------------ passender Eintrag existiert (CALL)         */
  690.   cpy6ch(&despoi->nodide[0], iden);    /* Ident umkopieren             */
  691.   unlink(despoi);        /* Eintrag aus Kette loesen             */
  692.  
  693.   for (ziel1  = (nodtyp *) destil.lnext;    /* Zielliste absuchen         */
  694.        ziel1 != (nodtyp *) &destil.lnext;
  695.        ziel1  = (nodtyp *) ziel1->nodlnk.lnext)
  696.     {
  697.       id1poi = (char *) &ziel1->nodide[0];
  698.       id2poi = (char *) &despoi->nodide[0];
  699.       for (cnt = 13; cnt != 0; --cnt)
  700.         {                /* Call und Ident vergleichen         */
  701.           if (*id1poi == *id2poi)
  702.             {
  703.               ++id1poi;
  704.               ++id2poi;
  705.             }
  706.           else break;
  707.         }                /* Call und Ident verglichen         */
  708.       if (*id1poi > *id2poi) break;
  709.     }                    /* Zielliste abgesucht             */
  710.   relink(despoi, ziel1->nodlnk.lprev);
  711.   if ((rout = istweg(digis, nachb, port)) == -1)
  712.     {
  713.       if (mode == '+')
  714.         newnod(obci, quali, port, digis, nachb);
  715.     }
  716.   else
  717.     {
  718.       if (mode == '-')
  719.         delrou(rout);
  720.       else
  721.         {
  722.           if (despoi->weg[rout].obscnt != 0)
  723.             addweg(obci, quali, rout);
  724.         }
  725.     }
  726.   return (TRUE);
  727.   }
  728.  
  729. /*---------------------------------------------------------------------------*/
  730. VOID    newnod(obci, quali, port, digis, nachb)
  731.                 /* Zieleintrag in Liste aufnehmen         */
  732. unsigned obci;            /* Anwesenheitszaehler                 */
  733. unsigned quali;            /* Qualitaet des Weges                 */
  734. unsigned port;            /* Port zum Ziel                 */
  735. char     *digis;        /* Digipeaterliste                 */
  736. char     *nachb;        /* Nachbar zum Ziel                 */
  737.   {
  738.   register unsigned  neuweg;    /* Position des neuen Weges in Liste         */
  739.   register wegtyp    *wegptr;    /* Pointer auf Weg                 */
  740.   register nbrtyp    *nbrptr;    /* Pointer auf Nachbarn                 */
  741.  
  742.   rouhin();            /* alle Wege in Arbeitsspeicher             */
  743.   (wegptr = &routmp[despoi->wege]) /* auf neuen Weg. wege zaehlt 1-2-3!         */
  744.          ->qualit = quali;    /* Qualitaet des neuen Weges             */
  745.   wegptr->obscnt = obci;    /* Anwesenheitszaehler                 */
  746.   wegptr->nachba = (nbrtyp *) -1; /* Zeiger auf Nachbarn loeschen         */
  747.   neuweg = srtrou(despoi->wege++); /* Wege sortieren                 */
  748.   rouher();            /* Wege zurueck in Liste             */
  749.   if (neuweg < 3)        /* steht der neue Weg in der Liste?         */
  750.     {
  751.       ++(nbrptr = updnbr(digis, nachb, port)) /* Nachbarnliste neuer Stand   */
  752.                   ->nbrrou;    /* ein Weg mehr ueber diesen Nachbarn         */
  753.       despoi->weg[neuweg].nachba = nbrptr; /* Nachbarn in Zielliste eintragen*/
  754.     }
  755.   if (despoi->wege > 3) {    /* nun mehr als 3 Wege vorhanden?         */
  756.     --despoi->wege;        /* darf nicht sein                 */
  757.     if (neuweg < 3)        /* wurde neuer Weg in die Liste aufgenommen? */
  758.       decrcn(&routmp[3]);    /* dann muss ein anderer entfernt werden     */
  759.     }
  760.   if ((despoi->actrou != 0)    /* besteht ein aktiver Weg?             */
  761.     && (despoi->wegnr > 2)) {    /* und ist es der nun schlechteste?         */
  762.     despoi->wegnr = 0;        /* dann den besten nehmen             */
  763.     makrou();            /* und Link neu aufbauen             */
  764.     }
  765.   }
  766.  
  767. /*---------------------------------------------------------------------------*/
  768. VOID    addweg(obci, quali, nummer)
  769.                 /* Weg in Liste aufnehmen             */
  770. unsigned obci;            /* Anwesenheitszaehler                 */
  771. unsigned quali;            /* Qualitaet des Weges                 */
  772. unsigned nummer;        /* Nummer des Eintrages                 */
  773.   {
  774.   register wegtyp *wegptr;    /* Pointer auf Weg                 */
  775.  
  776.   (wegptr = &(despoi->weg[nummer]))->qualit = quali; /* Qualitaet         */
  777.   wegptr->obscnt = obci;    /* und Anwesenheitszaehler setzen         */
  778.   rouhin();            /* auslagern in Arbeitsspeicher             */
  779.   srtrou(-1);            /* sortieren                     */
  780.   rouher();            /* zurueck in Liste                 */
  781.   }
  782.  
  783. /*---------------------------------------------------------------------------*/
  784. VOID    delrou(nummer)        /* Weg aus Liste streichen             */
  785. unsigned nummer;        /* Nummer des Eintrages                 */
  786.   {
  787.   register wegtyp *wegptr;    /* Pointer auf Weg                 */
  788.  
  789.   decrcn(wegptr = &(despoi->weg[nummer])); /* Weg in Nachbarnliste loeschen  */
  790.   if (despoi->wege > 1) {    /* nun noch Wege fuer dieses Ziel vorhanden? */
  791.     wegptr->nachba = 0;        /* ohne Nachbarn hat der Weg keine Qualitaet */
  792.     rouhin();            /* Wege in Arbeitsspeicher             */
  793.     srtrou(-1);            /* sortieren                     */
  794.     rouher();            /* wieder in Liste zurueck             */
  795.     }
  796.   else {            /* den letzten Weg entfernt             */
  797.     destot();            /* Ziel existiert nicht mehr             */
  798.     despoi->nodcal[0] = 0;    /* Eintrag ist wieder frei             */
  799.     }
  800.   if ((despoi->wegnr >= --despoi->wege) /* aktiven Weg geloescht?         */
  801.     && (despoi->actrou != 0)) {
  802.     despoi->wegnr = 0;        /* neuen Weg suchen                 */
  803.     makrou();
  804.     }
  805.   }
  806.  
  807. /*---------------------------------------------------------------------------*/
  808. VOID    decrcn(weg)        /* Weg aus Nachbarn-Liste streichen         */
  809. wegtyp    *weg;            /* zu loeschender Weg                 */
  810.   {
  811.   register nbrtyp *nbrptr;    /* Pointer auf Nachbarn                 */
  812.  
  813.   if ((--(nbrptr = weg->nachba)->nbrrou == 0) /* den letzten Weg geloescht?  */
  814.     && (nbrptr->locked == 0))    /* und Eintrag nicht gesperrt             */
  815.     {
  816.       dealoc(unlink(nbrptr));    /* dann Nachbarn komplett loeschen         */
  817.     }
  818.   }
  819.  
  820. /*---------------------------------------------------------------------------*/
  821. VOID    rouhin()        /* Wege in Arbeitsspeicher auslagern         */
  822.   {
  823.   move4b(3, routmp, &despoi->weg[0]); /* 12 (=3*4) Bytes kopieren         */
  824.   }
  825.  
  826. /*---------------------------------------------------------------------------*/
  827. VOID    rouher()        /* Wege aus Arbeitsspeicher holen         */
  828.   {
  829.   move4b(3, &despoi->weg[0], routmp); /* 12 (=3*4) Bytes kopieren         */
  830.   }
  831.  
  832. /*---------------------------------------------------------------------------*/
  833. unsigned srtrou(wegneu)        /* Wegeliste in routmp sortieren         */
  834. int    wegneu;            /* Position des neuen Weges in routmp         */
  835.                 /* Rueckgabe: Position des neuen Weges         */
  836.   {
  837.   unsigned wegcnt;        /* Zahl der Wege in routmp             */
  838.   unsigned waktiv;        /* aktiver Weg dieses Zieles             */
  839.   unsigned akt;            /* aktuell untersuchter Weg (Nummer)         */
  840.   register unsigned nxt;    /* naechster zu untersuchender Weg (Nummer)  */
  841.   register wegtyp   *wakt;    /* aktueller Weg                 */
  842.   register wegtyp   *wnxt;    /* naechster Weg                 */
  843.  
  844.   wegcnt = despoi->wege;    /* Zahl der Wege holen                 */
  845.   waktiv = despoi->wegnr;    /* aktiven Weg merken                 */
  846.   for (wakt = &routmp[akt = 0];    /* Bubble Sort ueber routmp             */
  847.        (wegcnt-1) > akt;
  848.        ++akt, ++wakt) {
  849.     for (wnxt = &routmp[nxt = akt + 1];
  850.          nxt < wegcnt;
  851.          ++nxt, ++wnxt) {
  852.       if ((! wakt->nachba)    /* der Weg muss einen Nachbarn haben         */
  853.         || ((wakt->qualit & 0xff) < (wnxt->qualit & 0xff))) { /* und besser  */
  854.         move4b(1, &rouwrk, wakt); /* als der vorherige sein             */
  855.         move4b(1, wakt, wnxt);    /* dann die Wege tauschen             */
  856.         move4b(1, wnxt, &rouwrk);
  857.         if (wegneu == akt) wegneu = nxt; /* neuen Weg merken             */
  858.         else if (wegneu == nxt) wegneu = akt;
  859.         if (waktiv == akt) waktiv = nxt; /* aktiven Weg merken             */
  860.         else if (waktiv == nxt) waktiv = akt;
  861.     } } }
  862.   despoi->wegnr = waktiv;    /* aktiven Weg in Liste korrigieren         */
  863.   return(wegneu);        /* mit Position des neuen Weges zurueck         */
  864.   }
  865.  
  866. /*---------------------------------------------------------------------------*/
  867. /* we have a macro version for this - so only use it if
  868.  * the macro has not been included.
  869.  */
  870. #ifndef move4b
  871. VOID    move4b(zahl, nach, von)    /* 4 * Zahl Bytes kopieren             */
  872. unsigned zahl;
  873. register char     *nach;        /* Ziel                         */
  874. register char     *von;        /* Quelle                     */
  875.   {
  876.   register unsigned cnt;    /* Scratch Zaehler                 */
  877.  
  878.   for (cnt = 0; (zahl * 4) > cnt; ++cnt) {
  879.     *nach++ = *von++;
  880.     }
  881.   }
  882. #endif
  883.  
  884. /*---------------------------------------------------------------------------*/
  885. VOID    todest(mbhd)        /* Info in Zielliste haengen             */
  886. mhtyp    *mbhd;            /* Info Header                     */
  887.   {
  888.   relink(mbhd, despoi->nodinf.lprev); /* Info umhaengen                 */
  889.   if (despoi->actrou == 0) {    /* kein aktiver Weg da?                 */
  890.     despoi->wegnr = 0;        /* mit dem besten Weg beginnend             */
  891.     makrou();            /* Link aufbauen                 */
  892.     }
  893.   }
  894.  
  895. /*---------------------------------------------------------------------------*/
  896. VOID    makrou()        /* Weg zu einem Ziel aufbauen             */
  897.   {
  898.   register unsigned  cnt;    /* Scratch Zaehler                 */
  899.   register l2ltyp    *l2poi;    /* Pointer auf Level2 Kontrollblock         */
  900.   register nbrtyp    *nbrpoi;    /* Pointer auf Nachbarn                 */
  901.  
  902.   if (despoi->nodinf.lnext != (lhtyp *) &despoi->nodinf.lnext) { /* Info?    */
  903.     despoi->actrou &= 0xfff8;    /* Status: kein aktiver Weg             */
  904.     if ((lnkpoi =         /* schon - noch Eintrag fuer L2 vorhanden?   */
  905.       (nbrpoi = despoi->weg[despoi->wegnr].nachba)->nbrl2l)
  906.       == 0) {
  907.       for (l2poi = 0, cnt = 0, lnkpoi = &lnktbl[0];
  908.            cnt < MAXL2L;    /* nein, freien Eintrag suchen             */
  909.            ++cnt, ++lnkpoi) {
  910.         if (lnkpoi->state != 0) { /* Eintrag belegt                 */
  911.           if ((cmpid(nbrpoi->nbrcal, lnkpoi->dstid) /*== 1*/)
  912.             &&(cmpid(myid, lnkpoi->srcid) /*== 1*/)
  913.             &&(lnkpoi->liport == nbrpoi->nbrpor))
  914.             break;        /* passt er zufaellig? Dann benutzen         */
  915.           }
  916.         else {            /* Eintrag ist frei                 */
  917.           if ((l2poi == 0) && (lnkpoi->srcid[0] == 0))
  918.             l2poi = lnkpoi;          /* ersten freien Eintrag merken    */
  919.           }
  920.         }
  921.       if (cnt == MAXL2L) {    /* kein passender Eintrag gefunden?         */
  922.         if (l2poi != 0) {    /* freier Eintrag vorhanden?             */
  923.           lnkpoi = l2poi;    /* dann nehmen wir ihn                 */
  924.           cpyid(lnkpoi->srcid, myid); /* Quellcall eintragen             */
  925.           cpyid(lnkpoi->dstid, nbrpoi->nbrcal); /* Zielcall eintragen         */
  926.           cpyidl(lnkpoi->viaid, nbrpoi->nbrdil); /* Digiliste eintragen         */
  927.           lnkpoi->liport = nbrpoi->nbrpor; /* Port eintragen             */
  928.           newlnk();        /* im Level 2 eine Verbindung bestellen         */
  929.           }
  930.         else {            /* L2 Tabelle ist voll                 */
  931.           despoi->actrou |= 0x02; /* Fehler markieren                 */
  932.           return;        /* Abbruch                     */
  933.           }
  934.         }
  935.       nbrpoi->nbrl2l = lnkpoi;    /* in Nachbarnliste Querverweis eintragen    */
  936.       }
  937.     if (lnkpoi->state == 1)    /* Status = Connect laeuft?             */
  938.       despoi->actrou |= 0x01;    /* dann auch in Nachbarnliste so markieren   */
  939.     else
  940.       {
  941.         if (lnkpoi->state == 3)    /* Status: Disc-Requested?             */
  942.           despoi->actrou |= 0x04;
  943.         else
  944.           despoi->actrou = 3;    /* sonst Status = connected             */
  945.       }
  946.     if ((despoi->actrou == 1)    /* Connect laeuft und                 */
  947.       && (despoi->wegnr == 0))    /* noch kein Weg probiert             */
  948.       despoi->actrou |= 0x80;    /* markieren                     */
  949.     }
  950.   else despoi->actrou = 0;    /* keine aktive Route                 */
  951.   }
  952.  
  953. /*---------------------------------------------------------------------------*/
  954. VOID    destot()        /* Ziel ist nicht mehr erreichbar         */
  955.   {
  956.   dealml(&despoi->nodinf);    /* Info fuer das Ziel wegwerfen             */
  957.   despoi->actrou = 0;        /* kein aktiver Weg                  */
  958.   }
  959.  
  960. /*---------------------------------------------------------------------------*/
  961. BOOLEAN isgood()        /* Entscheidung ueber Qualitaet des Weges    */
  962.   {                /* TRUE: Qualitaet ist gut fuer Speicherung  */
  963.     return (            /* FALSE: schlechter Weg             */
  964. #ifdef ACL
  965.       !( ( acl_mask & ACL_BAR_L3_BCASTS ) &&
  966.          ( acl_entry( &rxfhdr[7] ) & ACL_BAR_L3_BCASTS ) ) &&
  967. #endif
  968.       (qualty = (
  969.       (nbrpoi = getnei(&txfhdr[14], &rxfhdr[7], rxfprt)) /* welcher Nachbar? */
  970.         == NULL)?            /* existiert er ueberhaupt?         */
  971.         ((rxfprt == 0)? ch0qua : ch1qua) /* Portqualitaet, wenn nicht da     */
  972.         :
  973.         (nbrpoi->pathqu & 0xff))    /* sonst aus Nachbarliste         */
  974.       >= worqua);            /* vergleichen mit Minimalqualitaet  */
  975.   }
  976.  
  977. /*---------------------------------------------------------------------------*/
  978. nbrtyp    *updnbr(digis, nachb, port)    /* Nachbar auf neuen Stand bringen   */
  979.   char       *digis;            /* Digiliste zum Nachbarn         */
  980.   char     *nachb;            /* Call des Nachbarn             */
  981.   unsigned port;            /* Port zum Nachbarn             */
  982.   {
  983.   register nbrtyp   *nbrbuf;        /* Buffer fuer Eintrag             */
  984.  
  985.   if ((nbrbuf = getnei(digis, nachb, port)) == NULL)
  986.     {                    /* Eintrag existiert noch nicht         */
  987.       nbrbuf = (nbrtyp *) allocb();        /* Buffer beschaffen         */
  988.       cpyid(&nbrbuf->nbrcal[0], nachb);    /* Call eintragen             */
  989.       digis[14] = 0;            /* nur 2 Digis                 */
  990.       cpyidl(&nbrbuf->nbrdil[0], digis); /* Digiliste eintragen             */
  991.       nbrbuf->pathqu =
  992.         ((nbrbuf->nbrpor = port) == 0)?
  993.         ch0qua : ch1qua;
  994.       nbrbuf->locked =
  995.       nbrbuf->nbrrou = 0;
  996.       nbrbuf->nbrl2l = NULL;
  997.       relink(nbrbuf, neigbl.lprev);
  998.     }
  999.   return(nbrbuf);            /* mit Pointer auf Eintrag zurueck   */
  1000.   }
  1001.  
  1002. /*---------------------------------------------------------------------------*/
  1003. nbrtyp    *getnei(digis, name, port)    /* Nachbarn suchen             */
  1004.   char       *digis;
  1005.   char       *name;
  1006.   unsigned port;
  1007.   {
  1008.   register nbrtyp   *nachb;
  1009.  
  1010.     for (nachb  = (nbrtyp *) neigbl.lnext;
  1011.          nachb != (nbrtyp *) &neigbl.lnext;
  1012.          nachb  = (nbrtyp *) nachb->nbrlnk.lnext)
  1013.       {
  1014.         if (isneig(digis, name, port, nachb) /*== TRUE*/) 
  1015.             return (nachb);
  1016.       }
  1017.     return(NULL);
  1018.   }
  1019.  
  1020. /*---------------------------------------------------------------------------*/
  1021. nbrprt(call)            /* Port fuer Ziel "call" suchen?         */
  1022. char    *call;
  1023.   {
  1024.   register nbrtyp   *nachb;    /* aktueller Nachbar                 */
  1025.  
  1026.   for (nachb  = (nbrtyp *) neigbl.lnext;    /* Nachbarnliste absuchen    */
  1027.        nachb != (nbrtyp *) &neigbl.lnext;
  1028.        nachb  = (nbrtyp *) nachb->nbrlnk.lnext)
  1029.     {
  1030.       if (cmpid(call, nachb->nbrcal) /*== TRUE*/)
  1031.         {
  1032.           return(nachb->nbrpor);
  1033.         }
  1034.     }
  1035.  
  1036.   if (isidnt(call) /*== TRUE*/)
  1037.     {
  1038.       for (nachb  = (nbrtyp *) neigbl.lnext;
  1039.            nachb != (nbrtyp *) &neigbl.lnext;
  1040.            nachb  = (nbrtyp *) nachb->nbrlnk.lnext)
  1041.         {
  1042.           if (cmpid(&nachb->nbrcal[0], &despoi->nodcal[0]) /*== TRUE*/)
  1043.             return(nachb->nbrpor);
  1044.         }
  1045.     }
  1046.   return(0);            /* HDLC als default                 */
  1047.   }
  1048.  
  1049. /*---------------------------------------------------------------------------*/
  1050. BOOLEAN    iscall(call)        /* ist Call als Ziel eingetragen?         */
  1051. char    *call;
  1052.   {
  1053.   for (despoi  = (nodtyp *) destil.lnext;        /* Zielliste absuchen                 */
  1054.        despoi != (nodtyp *) &destil.lnext;
  1055.        despoi  = (nodtyp *) despoi->nodlnk.lnext) {
  1056.     if (despoi->nodcal[0] != 0) { /* Eintrag definiert?                 */
  1057.       if (cmpid(call, despoi->nodcal) /*== 1*/) /* dann testen             */
  1058.         return(TRUE);
  1059.     } }
  1060.   return(FALSE);
  1061.   }
  1062.  
  1063. /*---------------------------------------------------------------------------*/
  1064. BOOLEAN    isidnt(ident)        /* ist Ident als Ziel eingetragen?         */
  1065. char    *ident;
  1066.   {
  1067.   for (despoi  = (nodtyp *) destil.lnext;    /* Zielliste absuchen         */
  1068.        despoi != (nodtyp *) &destil.lnext;
  1069.        despoi  = (nodtyp *) despoi->nodlnk.lnext) {
  1070.     if (despoi->nodcal[0] != 0) { /* Eintrag definiert?                 */
  1071.       if (cmpcal(ident, despoi->nodide) /*== 1*/) /* dann testen             */
  1072.         return(TRUE);
  1073.     } }
  1074.   return(FALSE);
  1075.   }
  1076.  
  1077. /*---------------------------------------------------------------------------*/
  1078. istweg(digis, call, port)        /* Test, ob ein Weg existiert         */
  1079.   char       *digis;            /* Digiliste                 */
  1080.   char       *call;            /* Call des Nachbarn             */
  1081.   char       port;            /* Port fuer den Weg             */
  1082.   {                    /* Rueckgabe: Weg-Nummer         */
  1083.   register unsigned cnt;        /* Scratch Zaehler             */
  1084.  
  1085.   for (cnt = 0;
  1086.        cnt < despoi->wege;
  1087.        ++cnt)                /* alle Wege zum Ziel testen         */
  1088.     {
  1089.       if (isneig(digis, call, port, despoi->weg[cnt].nachba) /*== TRUE*/)
  1090.         return(cnt);
  1091.     }
  1092.   return(-1);                /* Fehler, nicht gefunden         */
  1093.   }
  1094.  
  1095. /*---------------------------------------------------------------------------*/
  1096. /* we do not need this if the more complex integrity checker is included
  1097.  */
  1098. #ifndef INTEGRITY
  1099. BOOLEAN    isrout(buffer)        /* Test, ob buffer in Weglisten ist         */
  1100. nbrtyp    *buffer;
  1101.   {
  1102.   register nbrtyp *nachb;
  1103.  
  1104.   for (nachb  = (nbrtyp *) neigbl.lnext;    /* Nachbarnliste absuchen    */
  1105.        nachb != (nbrtyp *) &neigbl.lnext;
  1106.        nachb  = (nbrtyp *) nachb->nbrlnk.lnext)
  1107.     {
  1108.       if (nachb == buffer) return(TRUE);
  1109.     }
  1110.  
  1111.   for (despoi  = (nodtyp *) destil.lnext;    /* Zielliste absuchen         */
  1112.        despoi != (nodtyp *) &destil.lnext;
  1113.        despoi  = (nodtyp *) despoi->nodlnk.lnext)
  1114.     {
  1115.       if (despoi == (nodtyp *) buffer) return(TRUE);
  1116.     }
  1117.   return(FALSE);        /* nicht gefunden                 */
  1118.   }
  1119. #endif
  1120.  
  1121. /*---------------------------------------------------------------------------*/
  1122. BOOLEAN    isneig(digis, call, port, nachb) /* Test, ob Daten in Nachbarliste   */
  1123. char    *digis;            /* Digipeaterliste                 */
  1124. char    *call;            /* Call                         */
  1125. char    port;            /* Port                         */
  1126. register nbrtyp    *nachb;        /* Pointer auf vermuteten Eintrag in Liste   */
  1127.   {
  1128.   return((nachb->nbrpor == port)
  1129.       && (cmpid(nachb->nbrcal, call) /*== 1*/)
  1130.       && (cmpidl(nachb->nbrdil, digis) /*== 1*/));
  1131.   }
  1132.  
  1133. /*---------------------------------------------------------------------------*/
  1134. BOOLEAN    ge6chr(buffer, mbhd)    /* 6 Zeichen aus mbhd nach Buffer         */
  1135. register char    *buffer;    /* Rueckgabe: TRUE=hat funktioniert         */
  1136. register mhtyp    *mbhd;
  1137.   {
  1138.   register unsigned cnt;    /* Zaehler                     */
  1139.  
  1140.   if ((mbhd->putcnt - mbhd->getcnt) >= 6) { /* genug Zeichen da?         */
  1141.     for (cnt = 6; cnt != 0; --cnt) {
  1142.       *buffer++ = getchr(mbhd);    /* Zeichen holen, ablegen             */
  1143.       }
  1144.     return(TRUE);        /* Erfolg melden                 */
  1145.     }
  1146.   else return(FALSE);        /* nicht genug Zeichen im mbhd             */
  1147.   }
  1148.  
  1149. /*---------------------------------------------------------------------------*/
  1150. VOID    pu6chr(buffer, mbhd)    /* 6 Zeichen aus Buffer in mbhd             */
  1151. register char    *buffer;
  1152. register mhtyp    *mbhd;
  1153.   {
  1154.   register unsigned cnt;    /* Zaehler                     */
  1155.  
  1156.   for (cnt = 6; cnt != 0; --cnt) {
  1157.     putchr(*buffer++, mbhd);
  1158.   } }
  1159.  
  1160. /*---------------------------------------------------------------------------*/
  1161. /* as for move4b, we have a quicker way of doing this .....
  1162.  * BUT BE CAREFUL - it is a macro so paramaters must be set carefully !
  1163.  */
  1164. #ifndef cpy6ch
  1165. VOID    cpy6ch(dest, src)
  1166. register   char    *src;
  1167. register   char    *dest;
  1168.   {
  1169.   register unsigned cnt;
  1170.  
  1171.   for (cnt = 0; cnt < 6; ++cnt)
  1172.     {
  1173.       *dest++ = *src++;
  1174.     }
  1175.   }
  1176. #endif
  1177.  
  1178. /*- Ende Level 3 ------------------------------------------------------------*/
  1179.